]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
parentalControlsManager: Add support for session limits
authorIgnacy Kuchciński <ignacykuchcinski@gnome.org>
Mon, 18 Aug 2025 09:44:42 +0000 (11:44 +0200)
committerIgnacy Kuchciński <ignacykuchcinski@gnome.org>
Wed, 5 Nov 2025 14:22:12 +0000 (15:22 +0100)
Add ability to check if session limits are enabled for users using API
introduced in malcontent 0.14.0. The `get_session_limits_async` function
is actually available since 0.5.0, but the signal
`session-limits-changed` was only introduced in 0.14.0, so check for
function `get_daily_limit` which was introduced in 0.14.0 to be sure
we're using correct version. This allows us to keep filtering apps, even
if the library version doesn't fully support session limits.

Will be used in the future to integrate parental controls session
limits.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3841>

js/misc/parentalControlsManager.js

index 3dfe13d5a8f933482ed7b9cb0322517140ad0446..f4b284120bb5bd7048022a4e13e242945433d1ee 100644 (file)
@@ -32,8 +32,13 @@ let Malcontent = null;
 if (HAVE_MALCONTENT) {
     ({default: Malcontent} = await import('gi://Malcontent?version=0'));
     Gio._promisify(Malcontent.Manager.prototype, 'get_app_filter_async');
+    Gio._promisify(Malcontent.Manager.prototype, 'get_session_limits_async');
 }
 
+// We require libmalcontent ≥ 0.14.0 for session limits
+const HAVE_MALCONTENT_0_14 = Malcontent &&
+    GObject.signal_lookup('session-limits-changed', Malcontent.Manager) > 0;
+
 let _singleton = null;
 
 /**
@@ -53,6 +58,7 @@ export function getDefault() {
 const ParentalControlsManager = GObject.registerClass({
     Signals: {
         'app-filter-changed': {},
+        'session-limits-changed': {},
     },
 }, class ParentalControlsManager extends GObject.Object {
     _init() {
@@ -61,6 +67,7 @@ const ParentalControlsManager = GObject.registerClass({
         this._initialized = false;
         this._disabled = false;
         this._appFilter = null;
+        this._sessionLimits = null;
 
         this._initializeManager();
     }
@@ -70,6 +77,7 @@ const ParentalControlsManager = GObject.registerClass({
             console.debug('Skipping parental controls support, malcontent not found');
             this._initialized = true;
             this.emit('app-filter-changed');
+            this.emit('session-limits-changed');
             return;
         }
 
@@ -77,16 +85,22 @@ const ParentalControlsManager = GObject.registerClass({
             const connection = await Gio.DBus.get(Gio.BusType.SYSTEM, null);
             this._manager = new Malcontent.Manager({connection});
             this._appFilter = await this._getAppFilter();
+
+            if (HAVE_MALCONTENT_0_14)
+                this._sessionLimits = await this._getSessionLimits();
         } catch (e) {
             logError(e, 'Failed to get parental controls settings');
             return;
         }
 
         this._manager.connect('app-filter-changed', this._onAppFilterChanged.bind(this));
+        if (HAVE_MALCONTENT_0_14)
+            this._manager.connect('session-limits-changed', this._onSessionLimitsChanged.bind(this));
 
         // Signal initialisation is complete.
         this._initialized = true;
         this.emit('app-filter-changed');
+        this.emit('session-limits-changed');
     }
 
     async _getAppFilter() {
@@ -123,6 +137,40 @@ const ParentalControlsManager = GObject.registerClass({
         }
     }
 
+    async _getSessionLimits() {
+        let sessionLimits = null;
+
+        try {
+            sessionLimits = await this._manager.get_session_limits_async(
+                Shell.util_get_uid(),
+                Malcontent.ManagerGetValueFlags.NONE,
+                null);
+        } catch (e) {
+            if (!e.matches(Malcontent.ManagerError, Malcontent.ManagerError.DISABLED))
+                throw e;
+
+            console.debug('Parental controls globally disabled');
+            this._disabled = true;
+        }
+
+        return sessionLimits;
+    }
+
+    async _onSessionLimitsChanged(manager, uid) {
+        // Emit 'changed' signal only if session-limits are changed for currently logged-in user
+        const currentUid = Shell.util_get_uid();
+        if (currentUid !== uid)
+            return;
+
+        try {
+            this._sessionLimits = await this._getSessionLimits();
+            this.emit('session-limits-changed');
+        } catch (e) {
+            // Keep the old session limits
+            logError(e, `Failed to get new MctSessionLimits for uid ${Shell.util_get_uid()} on session-limits-changed`);
+        }
+    }
+
     get initialized() {
         return this._initialized;
     }
@@ -152,4 +200,24 @@ const ParentalControlsManager = GObject.registerClass({
 
         return this._appFilter.is_appinfo_allowed(appInfo);
     }
+
+    /**
+     * Check whether parental controls session limits are enabled for the account,
+     * and if the library supports the features required for the functionality.
+     *
+     * @returns {bool} whether session limits are supported and enabled.
+     */
+    sessionLimitsEnabled() {
+        // Are latest parental controls enabled (at configure or runtime)?
+        if (!HAVE_MALCONTENT_0_14 || this._disabled)
+            return false;
+
+        // Have we finished initialising yet?
+        if (!this.initialized) {
+            console.debug('Ignoring session limits because parental controls not yet initialised');
+            return false;
+        }
+
+        return this._sessionLimits.is_enabled();
+    }
 });